#include <cstdio>
#include <iostream>
#include "HEpoll.h"
#include "AliasRef.h"

/**
 * 测试Client端功能
 */

#define CHKRET(r) if(r){printf(#r "=%d\n", r); return r;}
#define ELSEPRINT(tip, ...) else {printf("F: " tip "\n", ##__VA_ARGS__);}

atomic_int g_send_count(0);
atomic_int g_recv_count(0);
atomic_ullong g_send_bytes(0);
atomic_ullong g_recv_bytes(0);
chrono::steady_clock::time_point g_send_tbeg1;
chrono::steady_clock::time_point g_send_tbeg2;
chrono::steady_clock::time_point g_recv_tend;

int toTimeT(chrono::steady_clock::time_point tp)
{
    return tp.time_since_epoch().count();
}

void OnRespond(const string& msg, weak_ptr<ConnectMeta> wconnMeta)
{
    g_recv_bytes += msg.size();
    g_recv_count += 1;
    g_recv_tend = chrono::steady_clock::now();

    printf("recv=%llu bytes %d rows, time=%f(%d->%d->%d)\n", g_recv_bytes.load(), g_recv_count.load(),
        chrono::duration_cast<chrono::milliseconds>(g_recv_tend-g_send_tbeg1).count()/1000.0, 
        toTimeT(g_send_tbeg1), toTimeT(g_send_tbeg2), toTimeT(g_recv_tend));
}

int main(int argc, char** argv)
{
    if (argc < 3)
    {
        CHKRET(argc);
    }

    string svrHost(argv[1]);
    int svrPort = stoi(argv[2]);

    HEpoll hep;
    int ret = hep.init();
    CHKRET(ret);
    hep.setAliasNameInstance(make_shared<AliasRef<ConnectMetaSPtr>>());

    hep.run(true);

    string name0("cli-");
    string input;
    static int cIdx = 0;
    while (cin >> input, input != "q")
    {
        if ('c' == input[0])
        {
            int cCnt = input.size() > 1 ? stoi(input.c_str() +1) : 1;
            for (int i = 0; i < cCnt; i++)
            {
                auto conn = hep.addTcpConnect(svrHost, svrPort, 1, false);
                if (conn)
                {
                    hep.addAliasName(name0 + to_string(++cIdx), conn);
                    //int rSndBuf = conn->setSndBuffSize(10);
                    //int rRcvBuf = 0; //conn->setRcvBuffSize(10);
                    //printf("connect sndBuffSize %d rcvBuffSize=%d\n", rSndBuf, rRcvBuf);
                    conn->onMessageReachFunc = OnRespond;
                    //conn->sendMsg("begin test\n");
                    conn->start();
                }
                ELSEPRINT("addTcpConnect fail");
            }
            
        }
        else if ('s' == input[0])
        {
            int sCnt = stoi(input.c_str() + 1);
            if (sCnt > 0)
            {
                string datBuf(sCnt-1, '1');
                datBuf.append("2\n");
                g_send_tbeg1 = chrono::steady_clock::now();
                for (int i = 1; i <= cIdx; i++)
                {
                    string aliName = name0 + to_string(i);
                    auto conn = hep.find(aliName);
                    if (conn)
                    {
                        int muti = 3;
                        for (int i = 0; i < muti; i++)
                        {
                            if (0 == conn->sendMsg(datBuf))
                            {
                                g_send_count += 1;
                                g_send_bytes += datBuf.size() - 1;
                            }
                            ELSEPRINT("XXX sendMsg fail");
                        }
                        
                    }
                    ELSEPRINT("hep.find(%s) fail", aliName.c_str());
                }
            }

            g_send_tbeg2 = chrono::steady_clock::now();
            printf("sending=%llu bytes %d rows\n", g_send_bytes.load(), g_send_count.load());
        }
        else if ("r" == input)
        {
            g_send_count = 0;
            g_recv_count = 0;
            g_send_bytes = 0;
            g_recv_bytes = 0;
        }
        else if ('p' == input[0])
        {
            printf("hep status=%s\n", hep.toString().c_str());
            printf("send=%llu@%d  recv=%llu@%d\n", g_send_bytes.load(), g_send_count.load(),
                g_recv_bytes.load(), g_recv_count.load());
            printf("send_t1=%d send_t2=%d recv=%d %fsec\n", toTimeT(g_send_tbeg1), toTimeT(g_send_tbeg2), 
                toTimeT(g_recv_tend), chrono::duration_cast<chrono::milliseconds>(g_recv_tend-g_send_tbeg1).count()/1000.0);
            
            if (input[1] > 0)
            {
                string aliName = name0 + input.substr(1);
                auto connMeta = hep.find(aliName);
                if (connMeta)
                {
                    printf("%s : %s\n", aliName.c_str(), connMeta->toString().c_str());
                }
            }
        }
        

        //
        input.clear();
    }

    printf("notify Exit");
    hep.notifyExit();
    hep.unInit();
    return 0;
}